<?php

namespace App\Models\Trip\OrderPay;

use App\Trip\Traits\Pay\SubPayModelAttributeTrait;
use App\Trip\Wechat\Pay\PayRes\PayQuery;
use App\Trip\Wechat\Pay\WechatPay;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use Eloquent;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;

/**
 * App\Models\Trip\OrderPay\OrderPay
 *
 * @property int         $id
 * @property string      $user_id
 *           用户
 * @property string      $trip_id
 *           行程id
 * @property string      $pay_title
 *           支付标题
 * @property string      $pay_sn
 *           支付单号
 * @property string      $trade_sn
 *           支付流水号,支付后才知道
 * @property string      $pay_type
 *           支付类型 1 微信支付
 * @property string      $pay_amount
 *           总支付金额
 * @property string      $real_amount
 *           实际支付金额,支付后才知道
 * @property int         $pay_state
 *           支付状态 0待支付 1已支付 3已取消 2 失败
 * @property string      $trade_desc
 *           交易描述
 * @property string      $cancel_reason
 *           取消原因
 * @property string      $failed_reason
 *           失败原因
 * @property string      $mchid
 *           支付商戶id
 * @property string      $appid
 *           appid
 * @property Carbon|null $created_at
 * @property Carbon|null $updated_at
 * @property string      $business_type
 *           业务类型 10 下单, 11 改签 ,20  抢票 ,21 编辑抢票任务
 * @property-read Collection|OrderPayDetail[]
 *                $order_pay_details
 * @property-read int|null
 *                $order_pay_details_count
 * @method static Builder|OrderPay newModelQuery()
 * @method static Builder|OrderPay newQuery()
 * @method static Builder|OrderPay query()
 * @method static Builder|OrderPay whereAppid($value)
 * @method static Builder|OrderPay whereBusinessType($value)
 * @method static Builder|OrderPay whereCancelReason($value)
 * @method static Builder|OrderPay whereCreatedAt($value)
 * @method static Builder|OrderPay whereFailedReason($value)
 * @method static Builder|OrderPay whereId($value)
 * @method static Builder|OrderPay whereMchid($value)
 * @method static Builder|OrderPay wherePayAmount($value)
 * @method static Builder|OrderPay wherePaySn($value)
 * @method static Builder|OrderPay wherePayState($value)
 * @method static Builder|OrderPay wherePayTitle($value)
 * @method static Builder|OrderPay wherePayType($value)
 * @method static Builder|OrderPay whereRealAmount($value)
 * @method static Builder|OrderPay whereTradeDesc($value)
 * @method static Builder|OrderPay whereTradeSn($value)
 * @method static Builder|OrderPay whereTripId($value)
 * @method static Builder|OrderPay whereUpdatedAt($value)
 * @method static Builder|OrderPay whereUserId($value)
 * @mixin Eloquent
 */
class OrderPay extends Model
{
    use HasFactory, SubPayModelAttributeTrait;

    /**
     * 支付类型 1 微信
     */
    const PAY_TYPE_WECHAT = 1;
    /**
     *
     * 业务类型 10 下单, 11 改签 12 退票需支付 ,20  抢票 ,21 编辑抢票任务 22 升级加速包
     */
    const BUSINESS_TYPE_ORDER                = 10;
    const BUSINESS_TYPE_CHANGE               = 11;
    const BUSINESS_TYPE_REFUND_NEED_PAY      = 12;
    const BUSINESS_TYPE_SNAP                 = 20;
    const BUSINESS_TYPE_TASK_EDIT            = 21;
    const BUSINESS_TYPE_TASK_UPGRADE_LEVEL   = 22;
    const PAY_STATE_WAITING                  = 0; // 待支付
    const PAY_STATE_SUCCESS                  = 1; // 支付成功
    const PAY_STATE_FAILED                   = 2; // 支付失败
    const PAY_STATE_CANCEL                   = 3; // 已取消
    const PAY_STATE_BUSINESS_FAILED_REFUNDED = 4; // 支付成功 ,业务失败 已退款
    const PAY_STATE_NEED_REFUND              = 5; // 支付成功 ,需要退款 还未退款
    const PAY_STATE_SUCCESS_BUSINESS_ERROR   = 6; // 支付成功 ,标记业务失败 以便于后面管理

    protected $table = "order_pay";

    protected $fillable
        = [
            'user_id',
            'trip_id',
            'pay_title',
            'pay_sn',
            'trade_sn',
            'pay_type',
            'pay_amount',
            'real_amount',
            'pay_state',
            'trade_desc',
            'cancel_reason',
            'failed_reason',
            'mchid',
            'appid',
            'business_type',
        ];

    public function order_pay_details()
    {
        return $this->hasMany(OrderPayDetail::class, 'pay_sn', 'pay_sn');
    }

    public function getBusinessType(): int
    {
        return $this->getAttribute('business_type');
    }

    /**
     * 此金额只存微信返回的金额
     * @return float
     */
    public function getRealAmount(): float
    {
        return $this->getAttribute('real_amount');
    }


    public function isWaitingPay(): bool
    {
        return $this->getPayState() == self::PAY_STATE_WAITING;
    }


    /**
     * @throws InvalidArgumentException
     */
    public function getPayResultData(): array
    {
        return $this->getPayResult()->getQueryResult();
    }

    /**
     * @throws InvalidArgumentException
     * @throws Exception
     */
    public function getPayResult(): ?PayQuery
    {
        if ($this->getPayType() == self::PAY_TYPE_WECHAT) {
            $wechatPay = new WechatPay([
                "mchid" => $this->getMchId(),
            ]);
            return (new PayQuery($wechatPay->getApplication()))->setOutTradeNo($this->getPaySn());
        }

        throw new Exception("支付类型不存在");
    }

    /**
     * @throws InvalidArgumentException
     */
    public function isPayResultDataSuccess(): bool
    {

        $result = $this->getPayResult();
        if (!$result) {
            return false;
        }
        return $result->isSuccess();
    }

    /**
     * 获取（微信）支付回调单号
     *
     * @return string
     */
    public function getTradeSn(): string
    {
        return $this->getAttribute('trade_sn');
    }

    public function isPaid(): bool
    {
        return $this->isPaySuccess();
    }


    public function isPayCancel(): bool
    {
        return $this->getPayState() == self::PAY_STATE_CANCEL;
    }

    public function isPayFailed(): bool
    {
        return $this->getPayState() == self::PAY_STATE_FAILED;
    }


}
